﻿using System;

namespace QAToolsAddin {
    internal class TimeInfo {
        internal static Item[] GetItems() {
            return new Item[]{
	            new Item("-12:00 International Date Line West", -720, null, null),
	            new Item("-11:00 Samoa", -660, new BiasDate(4, 1, 6, 23, 59, 59), new BiasDate(9, 5, 6, 23, 59, 59)),
	            new Item("-11:00 Coordinated Universal Time-11", -660, null, null),
	            new Item("-10:00 Hawaii", -600, null, null),
	            new Item("-09:00 Alaska", -540, new BiasDate(11, 1, 0, 2, 0, 0), new BiasDate(3, 2, 0, 2, 0, 0)),
	            new Item("-08:00 Baja California", -480, new BiasDate(10, 5, 0, 2, 0, 0), new BiasDate(4, 1, 0, 2, 0, 0)),
	            new Item("-08:00 Pacific Time (US & Canada", -480, new BiasDate(11, 1, 0, 2, 0, 0), new BiasDate(3, 2, 0, 2, 0, 0)),
	            new Item("-07:00 Arizona", -420, null, null),
	            new Item("-07:00 Chihuahua, La Paz, Mazatlan - New", -420, new BiasDate(10, 5, 0, 2, 0, 0), new BiasDate(4, 1, 0, 2, 0, 0)),
	            new Item("-07:00 Chihuahua, La Paz, Mazatlan - Old", -420, new BiasDate(10, 5, 0, 2, 0, 0), new BiasDate(4, 1, 0, 2, 0, 0)),
	            new Item("-07:00 Mountain Time (US & Canada", -420, new BiasDate(11, 1, 0, 2, 0, 0), new BiasDate(3, 2, 0, 2, 0, 0)),
	            new Item("-06:00 Guadalajara, Mexico City, Monterrey - Old", -360, new BiasDate(10, 5, 0, 2, 0, 0), new BiasDate(4, 1, 0, 2, 0, 0)),
	            new Item("-06:00 Central Time (US & Canada", -360, new BiasDate(11, 1, 0, 2, 0, 0), new BiasDate(3, 2, 0, 2, 0, 0)),
	            new Item("-06:00 Saskatchewan", -360, null, null),
	            new Item("-06:00 Guadalajara, Mexico City, Monterrey - New", -360, new BiasDate(10, 5, 0, 2, 0, 0), new BiasDate(4, 1, 0, 2, 0, 0)),
	            new Item("-06:00 Central America", -360, null, null),
	            new Item("-05:00 Bogota, Lima, Quito", -300, null, null),
	            new Item("-05:00 Indiana (East", -300, new BiasDate(11, 1, 0, 2, 0, 0), new BiasDate(3, 2, 0, 2, 0, 0)),
	            new Item("-05:00 Eastern Time (US & Canada", -300, new BiasDate(11, 1, 0, 2, 0, 0), new BiasDate(3, 2, 0, 2, 0, 0)),
	            new Item("-04:30 Caracas", -270, null, null),
	            new Item("-04:00 Atlantic Time (Canada", -240, new BiasDate(11, 1, 0, 2, 0, 0), new BiasDate(3, 2, 0, 2, 0, 0)),
	            new Item("-04:00 Cuiaba", -240, new BiasDate(2, 3, 6, 23, 59, 59), new BiasDate(10, 3, 6, 23, 59, 59)),
	            new Item("-04:00 Asuncion", -240, new BiasDate(4, 2, 6, 23, 59, 59), new BiasDate(10, 1, 6, 23, 59, 59)),
	            new Item("-04:00 Santiago", -240, new BiasDate(3, 2, 6, 23, 59, 59), new BiasDate(10, 2, 6, 23, 59, 59)),
	            new Item("-04:00 Georgetown, La Paz, Manaus, San Juan", -240, null, null),
	            new Item("-03:30 Newfoundland", -210, new BiasDate(11, 1, 0, 0, 1, 0), new BiasDate(3, 2, 0, 0, 1, 0)),
	            new Item("-03:00 Buenos Aires", -180, null, null),
	            new Item("-03:00 Montevideo", -180, new BiasDate(3, 2, 0, 2, 0, 0), new BiasDate(10, 1, 0, 2, 0, 0)),
	            new Item("-03:00 Brasilia", -180, new BiasDate(2, 3, 6, 23, 59, 59), new BiasDate(10, 3, 6, 23, 59, 59)),
	            new Item("-03:00 Greenland", -180, new BiasDate(10, 5, 6, 23, 0, 0), new BiasDate(3, 5, 6, 22, 0, 0)),
	            new Item("-03:00 Cayenne, Fortaleza", -180, null, null),
	            new Item("-02:00 Coordinated Universal Time-02", -120, null, null),
	            new Item("-02:00 Mid-Atlantic", -120, new BiasDate(9, 5, 0, 2, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("-01:00 Azores", -60, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("-01:00 Cape Verde Is.", -60, null, null),
	            new Item("Coordinated Universal Time", 0, null, null),
	            new Item("+00:00 Dublin, Edinburgh, Lisbon, London", 0, new BiasDate(10, 5, 0, 2, 0, 0), new BiasDate(3, 5, 0, 1, 0, 0)),
	            new Item("+00:00 Monrovia, Reykjavik", 0, null, null),
	            new Item("+00:00 Casablanca", 0, null, null),
	            new Item("+01:00 Brussels, Copenhagen, Madrid, Paris", 60, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+01:00 Sarajevo, Skopje, Warsaw, Zagreb", 60, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+01:00 Belgrade, Bratislava, Budapest, Ljubljana, Prague", 60, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+01:00 West Central Africa", 60, null, null),
	            new Item("+01:00 Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna", 60, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+02:00 Cairo", 120, new BiasDate(9, 5, 4, 23, 59, 59), new BiasDate(4, 5, 4, 23, 59, 59)),
	            new Item("+02:00 Amman", 120, new BiasDate(10, 5, 5, 1, 0, 0), new BiasDate(3, 5, 4, 23, 59, 59)),
	            new Item("+02:00 Minsk", 120, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+02:00 Damascus", 120, new BiasDate(10, 5, 4, 23, 59, 59), new BiasDate(3, 5, 4, 23, 59, 59)),
	            new Item("+02:00 Jerusalem", 120, new BiasDate(10, 1, 0, 2, 0, 0), new BiasDate(4, 1, 5, 2, 0, 0)),
	            new Item("+02:00 Harare, Pretoria", 120, null, null),
	            new Item("+02:00 Athens, Bucharest, Istanbul", 120, new BiasDate(10, 5, 0, 4, 0, 0), new BiasDate(3, 5, 0, 3, 0, 0)),
	            new Item("+02:00 Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius", 120, new BiasDate(10, 5, 0, 4, 0, 0), new BiasDate(3, 5, 0, 3, 0, 0)),
	            new Item("+02:00 Beirut", 120, new BiasDate(10, 5, 6, 23, 59, 59), new BiasDate(3, 5, 6, 23, 59, 59)),
	            new Item("+01:00 Windhoek", 120, new BiasDate(9, 1, 0, 2, 0, 0), new BiasDate(4, 1, 0, 2, 0, 0)),
	            new Item("+03:00 Kuwait, Riyadh", 180, null, null),
	            new Item("+03:00 Nairobi", 180, null, null),
	            new Item("+03:00 Baghdad", 180, null, null),
	            new Item("+03:00 Moscow, St. Petersburg, Volgograd", 180, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+03:30 Tehran", 210, new BiasDate(9, 3, 1, 23, 59, 59), new BiasDate(3, 3, 6, 23, 59, 59)),
	            new Item("+04:00 Baku", 240, new BiasDate(10, 5, 0, 5, 0, 0), new BiasDate(3, 5, 0, 4, 0, 0)),
	            new Item("+04:00 Tbilisi", 240, null, null),
	            new Item("+04:00 Port Louis", 240, null, null),
	            new Item("+04:00 Caucasus Standard Time", 240, null, null),
	            new Item("+04:00 Abu Dhabi, Muscat", 240, null, null),
	            new Item("+04:00 Yerevan", 240, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+04:30 Kabul", 270, null, null),
	            new Item("+05:00 Islamabad, Karachi", 300, null, null),
	            new Item("+05:00 Ekaterinburg", 300, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+05:00 Tashkent", 300, null, null),
	            new Item("+05:30 Sri Jayawardenepura", 330, null, null),
	            new Item("+05:30 Chennai, Kolkata, Mumbai, New Delhi", 330, null, null),
	            new Item("+05:45 Kathmandu", 345, null, null),
	            new Item("+06:00 Dhaka", 360, null, null),
	            new Item("+06:00 Astana", 360, null, null),
	            new Item("+06:00 Novosibirsk", 360, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+06:30 Yangon (Rangoon", 390, null, null),
	            new Item("+07:00 Bangkok, Hanoi, Jakarta", 420, null, null),
	            new Item("+07:00 Krasnoyarsk", 420, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+08:00 Kuala Lumpur, Singapore", 480, null, null),
	            new Item("+08:00 Perth", 480, null, null),
	            new Item("+08:00 Beijing, Chongqing, Hong Kong, Urumqi", 480, null, null),
	            new Item("+08:00 Taipei", 480, null, null),
	            new Item("+08:00 Ulaanbaatar", 480, null, null),
	            new Item("+08:00 Irkutsk", 480, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+09:00 Osaka, Sapporo, Tokyo", 540, null, null),
	            new Item("+09:00 Seoul", 540, null, null),
	            new Item("+09:00 Yakutsk", 540, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+09:30 Darwin", 570, null, null),
	            new Item("+09:30 Adelaide", 570, new BiasDate(4, 1, 0, 3, 0, 0), new BiasDate(10, 1, 0, 2, 0, 0)),
	            new Item("+10:00 Brisbane", 600, null, null),
	            new Item("+10:00 Hobart", 600, new BiasDate(4, 1, 0, 3, 0, 0), new BiasDate(10, 1, 0, 2, 0, 0)),
	            new Item("+10:00 Guam, Port Moresby", 600, null, null),
	            new Item("+10:00 Vladivostok", 600, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+10:00 Canberra, Melbourne, Sydney", 600, new BiasDate(4, 1, 0, 3, 0, 0), new BiasDate(10, 1, 0, 2, 0, 0)),
	            new Item("+11:00 Magadan, Solomon Is., New Caledonia", 660, null, null),
	            new Item("+12:00 Coordinated Universal Time+12", 720, null, null),
	            new Item("+12:00 Fiji", 720, new BiasDate(3, 5, 0, 3, 0, 0), new BiasDate(10, 4, 0, 2, 0, 0)),
	            new Item("+12:00 Auckland, Wellington", 720, new BiasDate(4, 1, 0, 3, 0, 0), new BiasDate(9, 5, 0, 2, 0, 0)),
	            new Item("+12:00 Petropavlovsk-Kamchatsky - Old", 720, new BiasDate(10, 5, 0, 3, 0, 0), new BiasDate(3, 5, 0, 2, 0, 0)),
	            new Item("+13:00 Nuku'alofa", 780, null, null),
            };
        }

        internal class BiasDate {
            internal int Month { get; set; }
            internal int DayOccurence { get; set; }
            internal int DayOfWeek { get; set; }
            internal int Hour { get; set; }
            internal int Minute { get; set; }
            internal int Second { get; set; }

            internal BiasDate(int month, int day, int dayOfWeek, int hour, int minute, int second) {
                Month = month;
                DayOccurence = day;
                DayOfWeek = dayOfWeek;
                Hour = hour;
                Minute = minute;
                Second = second;
            }
        }

        public class Item {
            private string _name;
            private BiasDate _standardDate;
            private BiasDate _daylightDate;
            private int _bias;

            internal Item(string name, int bias, BiasDate standardDate, BiasDate daylightDate) {
                _name = name;
                _standardDate = standardDate;
                _daylightDate = daylightDate;
                _bias = bias;
            }

            private DateTime AddDayOccurrence(DateTime firstDayOfMonth, int dayOfWeek, int occurrenceNumber) {
                return firstDayOfMonth.AddDays((7 - ((int)firstDayOfMonth.DayOfWeek - (int)dayOfWeek)) % 7 + 7 * (occurrenceNumber - 1));

            }

            private int GetDayLigthBias(DateTime datetime) {
                if (this._daylightDate != null) {
                    DateTime daylightDate = new DateTime(datetime.Year, _daylightDate.Month, 1, _daylightDate.Hour, _daylightDate.Minute, _daylightDate.Second);
                    daylightDate = AddDayOccurrence(daylightDate, _daylightDate.DayOfWeek, _daylightDate.DayOccurence);
                    if (datetime > daylightDate) {
                        DateTime standartDate = new DateTime(datetime.Year, _standardDate.Month, 1, _standardDate.Hour, _standardDate.Minute, _standardDate.Second);
                        standartDate = AddDayOccurrence(standartDate, _standardDate.DayOfWeek, _standardDate.DayOccurence);
                        if (datetime < standartDate)
                            return _bias + 60;
                    }
                }
                return _bias;
            }

            public DateTime ToUTC(DateTime localDateTime) {
                return localDateTime.AddMinutes(-GetDayLigthBias(localDateTime));
            }

            public DateTime ToLocal(DateTime utcDateTime) {
                return utcDateTime.AddMinutes(GetDayLigthBias(utcDateTime));
            }

            public override string ToString() {
                return _name;
            }
        }
    }
}
